
#include "stdafx.h"

const TCHAR syslog_params_t::regpath_default[ ] = { _T( "Software\\CodePlex\\WindowsSysLog" ) };
const TCHAR syslog_params_t::logpath_default[ ] = { _T( "." ) };
const TCHAR syslog_params_t::logname_default[ ] = { _T( "syslog_" ) };
const TCHAR syslog_params_t::logextension_default[ ] = { _T( ".txt" ) };
const byte syslog_params_t::replacement_default = '^';
const byte syslog_params_t::filter_default = 7;
const byte syslog_params_t::own_filter_default = 8;
IN_ADDR syslog_params_t::address_any;
IN_ADDR syslog_params_t::address_loopback;

bool syslog_params_t::init( int argc, TCHAR** argv )
{
	cmd_line.argc = argc;
	cmd_line.argv = argv;

	_tcscpy_s( regpath, regpath_default );
	regpath_set = false;
	no_reg = false;

	no_dump = false;
	no_run = false;

	have_console = ( GetStdHandle( STD_OUTPUT_HANDLE ) != nullptr );
	using_stdout = have_console;
	running_as_a_service = ! have_console;

	_tcscpy_s( logpath, logpath_default );
	logpath_set = false;

	_tcscpy_s( logname, logname_default );
	logname_set = false;

	_tcscpy_s( logextension, logextension_default );
	logextension_set = false;

	logrotate_condition = to_day;
	logextension_set = false;

	replacement = replacement_default;
	replacement_set = false;

	filter = filter_default;
	filter_set = false;

	own_filter = own_filter_default;
	own_filter_set = false;

	log_date = false;
	log_date_set = false;

	log_time = true;
	log_time_set = false;

	log_msec = true;
	log_msec_set = false;

	log_ip = true;
	log_ip_set = false;

	newline_with_CR = true;
	newline_with_CR_set = false;

	mark_as_readonly = true;
	mark_as_readonly_set = false;

	flush = true;
	flush_set = false;

	num_regex = 0;

	address_any.s_addr = INADDR_ANY;
	address_loopback.s_addr = htonl( INADDR_LOOPBACK );
	address = address_any;
	address_set = false;

	port = htons( 514 );
	port_set = false;

	for( int i = 0; i < argc; ++i )
		if( argv[ i ] && argv[ i ][ 0 ] == _T( '-' ) )
		{
			if( _tcsicmp( argv[ i ], _T( "-regpath" ) ) == 0 )
			{
				if( ++i < argc )
				{
					if( _tcsncpy_s( regpath, argv[ i ], _TRUNCATE ) == 0 )
						regpath_set = true;
					else
						return false;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-noreg" ) ) == 0 )
			{
				no_reg = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-nodump" ) ) == 0 )
			{
				no_dump = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-norun" ) ) == 0 )
			{
				no_run = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-nostdout" ) ) == 0 )
			{
				using_stdout = false;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logpath" ) ) == 0 )
			{
				if( ++i < argc )
				{
					if( _tcsncpy_s( logpath, argv[ i ], _TRUNCATE ) == 0 )
						logpath_set = true;
					else
						return false;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logname" ) ) == 0 )
			{
				if( ++i < argc )
				{
					if( _tcsncpy_s( logname, argv[ i ], _TRUNCATE ) == 0 )
						logname_set = true;
					else
						return false;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logext" ) ) == 0 )
			{
				if( ++i < argc )
				{
					if( _tcsncpy_s( logextension, argv[ i ], _TRUNCATE ) == 0 )
						logextension_set = true;
					else
						return false;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logrotate" ) ) == 0 )
			{
				logrotate_condition_set = true;

				if( ++i < argc )
				{
					if( _tcsicmp( argv[ i ], _T( "yearly" ) ) == 0 )
						logrotate_condition = to_year;
					else if( _tcsicmp( argv[ i ], _T( "monthly" ) ) == 0 )
						logrotate_condition = to_month;
					else if( _tcsicmp( argv[ i ], _T( "daily" ) ) == 0 )
						logrotate_condition = to_day;
					else if( _tcsicmp( argv[ i ], _T( "hourly" ) ) == 0 )
						logrotate_condition = to_hour;
					else if( _tcsicmp( argv[ i ], _T( "minutely" ) ) == 0 )
						logrotate_condition = to_minute;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-filter" ) ) == 0 )
			{
				filter_set = true;

				if( ++i < argc )
				{
					int f = _tstoi( argv[ i ] );
					if( 0 <= f && f <= 255 )
						filter = byte( f );
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-ownfilter" ) ) == 0 )
			{
				own_filter_set = true;

				if( ++i < argc )
				{
					int f = _tstoi( argv[ i ] );
					if( 0 <= f && f <= 255 )
						own_filter = byte( f );
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logdate" ) ) == 0 )
			{
				log_date = true;
				log_date_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-nodate" ) ) == 0 )
			{
				log_date = false;
				log_date_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logtime" ) ) == 0 )
			{
				log_time = true;
				log_time_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-notime" ) ) == 0 )
			{
				log_time = false;
				log_time_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logmsec" ) ) == 0 )
			{
				log_msec = true;
				log_msec_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-nomsec" ) ) == 0 )
			{
				log_msec = false;
				log_msec_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-logip" ) ) == 0 )
			{
				log_ip = true;
				log_ip_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-noip" ) ) == 0 )
			{
				log_ip = false;
				log_ip_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-wineol" ) ) == 0 )
			{
				newline_with_CR = true;
				newline_with_CR_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-nixeol" ) ) == 0 )
			{
				newline_with_CR = false;
				newline_with_CR_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-setreadonly" ) ) == 0 )
			{
				mark_as_readonly = true;
				mark_as_readonly_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-noreadonly" ) ) == 0 )
			{
				mark_as_readonly = false;
				mark_as_readonly_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-flush" ) ) == 0 )
			{
				flush = true;
				flush_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-noflush" ) ) == 0 )
			{
				flush = false;
				flush_set = true;

				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-drop" ) ) == 0 )
			{
				if( ++i < argc && argv[ i ][ 0 ] && num_regex < max_regex )
				{
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, WSL_DBG_PREFIX _T( "argv[ ]: {%s}\t" ), argv[ i ] );
#endif
#if defined ( UNICODE )
					char default_char = '~';
					BOOL replacement_occured = false;

					if(
						WideCharToMultiByte(
							20127,	// us-ascii
							0,
							argv[ i ],
							-1,		// -1 if the string is null-terminated
							regex_tests[ num_regex ].regex.expression,
							syslog_regex_t::max_len,
							&default_char,
							&replacement_occured
						) == 0
					)
						return false;

#else
					size_t s = strlen( argv[ i ] );
					if(
						syslog_regex_t::max_len < ( s + 1 ) ||
						strncpy_s( regex_tests[ num_regex ].regex.expression, syslog_regex_t::max_len, argv[ i ], s ) != 0
					)
						return false;
#endif
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, _T( "regex.expression: {%hs}\n" ), regex_tests[ num_regex ].regex.expression );
#endif
					regex_tests[ num_regex ].mode = regex_mode::drop;

					++num_regex;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-trim" ) ) == 0 )
			{
				if( ++i < argc && argv[ i ][ 0 ] && num_regex < max_regex )
				{
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, WSL_DBG_PREFIX _T( "argv[ ]: {%s}\t" ), argv[ i ] );
#endif
#if defined ( UNICODE )
					char default_char = '?';
					BOOL replacement_occured = false;

					if(
						WideCharToMultiByte(
							20127,	// us-ascii
							0,
							argv[ i ],
							-1,		// -1 if the string is null-terminated
							regex_tests[ num_regex ].regex.expression,
							syslog_regex_t::max_len,
							&default_char,
							&replacement_occured
						) == 0
					)
						return false;

#else
					size_t s = strlen( argv[ i ] );
					if(
						syslog_regex_t::max_len < ( s + 1 ) ||
						strncpy_s( regex_tests[ num_regex ].regex.expression, syslog_regex_t::max_len, argv[ i ], s ) != 0
					)
						return false;
#endif
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, _T( "regex.expression: {%hs}\n" ), regex_tests[ num_regex ].regex.expression );
#endif
					regex_tests[ num_regex ].mode = regex_mode::trim;

					++num_regex;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-pass" ) ) == 0 )
			{
				if( ++i < argc && argv[ i ][ 0 ] && num_regex < max_regex )
				{
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, WSL_DBG_PREFIX _T( "argv[ ]: {%s}\t" ), argv[ i ] );
#endif
#if defined ( UNICODE )
					char default_char = '?';
					BOOL replacement_occured = false;

					if(
						WideCharToMultiByte(
							20127,	// us-ascii
							0,
							argv[ i ],
							-1,		// -1 if the string is null-terminated
							regex_tests[ num_regex ].regex.expression,
							syslog_regex_t::max_len,
							&default_char,
							&replacement_occured
						) == 0
					)
						return false;

#else
					size_t s = strlen( argv[ i ] );
					if(
						syslog_regex_t::max_len < ( s + 1 ) ||
						strncpy_s( regex_tests[ num_regex ].regex.expression, syslog_regex_t::max_len, argv[ i ], s ) != 0
					)
						return false;
#endif
#if defined ( WINDOWSSYSLOG_DEBUG )
					_ftprintf( WSL_DBG_STREAM, _T( "regex.expression: {%hs}\n" ), regex_tests[ num_regex ].regex.expression );
#endif
					regex_tests[ num_regex ].mode = regex_mode::pass;

					++num_regex;
				}
				continue;
			}

			if( _tcsicmp( argv[ i ], _T( "-port" ) ) == 0 )
			{
				port_set = true;

				if( ++i < argc )
				{
					int p = _tstoi( argv[ i ] );
					if( 1 <= p && p <= 65535 )
						port = htons( u_short( p ) );
				}
				continue;
			}

		}


	HKEY reg_key = nullptr;

	if(
		no_reg ||
		RegOpenKeyEx(
			HKEY_LOCAL_MACHINE,
			regpath,
			0,
			KEY_READ,
			&reg_key
		) != ERROR_SUCCESS
	)
		return true;

	if( !logpath_set )
		logpath_set =
			get_reg_value( reg_key, _T( "SysLogPath" ), logpath, SYSLOG_MAX_PATH );

	if( !logname_set )
		logname_set =
			get_reg_value( reg_key, _T( "SysLogName" ), logname, SYSLOG_MAX_PATH );

	if( !logextension_set )
		logextension_set =
			get_reg_value( reg_key, _T( "SysLogExtension" ), logextension, SYSLOG_MAX_PATH );

	if( !logrotate_condition_set )
	{
		TCHAR SysLogRotate[ SYSLOG_MAX_PATH ];

		if( get_reg_value( reg_key, _T( "SysLogRotate" ), SysLogRotate, SYSLOG_MAX_PATH ) )
		{
			logrotate_condition_set = true;

			if( _tcsicmp( SysLogRotate, _T( "yearly" ) ) == 0 )
				logrotate_condition = to_year;
			else if( _tcsicmp( SysLogRotate, _T( "monthly" ) ) == 0 )
				logrotate_condition = to_month;
			else if( _tcsicmp( SysLogRotate, _T( "daily" ) ) == 0 )
				logrotate_condition = to_day;
			else if( _tcsicmp( SysLogRotate, _T( "hourly" ) ) == 0 )
				logrotate_condition = to_hour;
			else if( _tcsicmp( SysLogRotate, _T( "minutely" ) ) == 0 )
				logrotate_condition = to_minute;
		}
	}

	if( !filter_set )
	{
		DWORD SeverityFilter = 0;

		if( get_reg_value( reg_key, _T( "SeverityFilter" ), &SeverityFilter ) )
		{
			if( 0 <= SeverityFilter && SeverityFilter <= 255 )
				filter = byte( SeverityFilter );
			else
				filter = filter_default;
			filter_set = true;
		}
	}

	if( !own_filter_set )
	{
		DWORD SeverityOwnFilter = 0;

		if( get_reg_value( reg_key, _T( "SeverityOwnFilter" ), &SeverityOwnFilter ) )
		{
			if( 0 <= SeverityOwnFilter && SeverityOwnFilter <= 255 )
				own_filter = byte( SeverityOwnFilter );
			else
				own_filter = own_filter_default;
			own_filter_set = true;
		}
	}

	if( !log_date_set )
	{
		DWORD LogDate = 0;

		if( get_reg_value( reg_key, _T( "LogDate" ), &LogDate ) )
		{
			log_date = ( LogDate != 0 );
			log_date_set = true;
		}
	}

	if( !log_time_set )
	{
		DWORD LogTime = 0;

		if( get_reg_value( reg_key, _T( "LogTime" ), &LogTime ) )
		{
			log_time = ( LogTime != 0 );
			log_time_set = true;
		}
	}

	if( !log_msec_set )
	{
		DWORD LogMilliseconds = 0;

		if( get_reg_value( reg_key, _T( "LogMilliseconds" ), &LogMilliseconds ) )
		{
			log_msec = ( LogMilliseconds != 0 );
			log_msec_set = true;
		}
	}

	if( !log_ip_set )
	{
		DWORD LogIP = 0;

		if( get_reg_value( reg_key, _T( "LogIP" ), &LogIP ) )
		{
			log_ip = ( LogIP != 0 );
			log_ip_set = true;
		}
	}

	if( !newline_with_CR_set )
	{
		DWORD WindowsNewLine = 0;

		if( get_reg_value( reg_key, _T( "WindowsNewLine" ), &WindowsNewLine ) )
		{
			newline_with_CR = ( WindowsNewLine != 0 );
			newline_with_CR_set = true;
		}
	}

	if( !mark_as_readonly_set )
	{
		DWORD SysLogMarkReadonly = 0;

		if( get_reg_value( reg_key, _T( "SysLogMarkReadonly" ), &SysLogMarkReadonly ) )
		{
			mark_as_readonly = ( SysLogMarkReadonly != 0 );
			mark_as_readonly_set = true;
		}
	}

	if( !flush_set )
	{
		DWORD Flush = 0;

		if( get_reg_value( reg_key, _T( "Flush" ), &Flush ) )
		{
			flush = ( Flush != 0 );
			flush_set = true;
		}
	}

	if( !port_set )
	{
		DWORD SysLogPort = 0;

		if( get_reg_value( reg_key, _T( "SysLogPort" ), &SysLogPort ) )
		{
			port = htons( u_short( SysLogPort ) );
			port_set = true;
		}
	}

	RegCloseKey( reg_key );


	return true;
}

void syslog_params_t::dump( )
{
#if defined ( WINDOWSSYSLOG_DEBUG )
#if defined ( UNICODE ) || defined ( _UNICODE )
	_ftprintf( WSL_DBG_STREAM, _T( "The UNICODE/_UNICODE macro has been defined.\n" ) );
#else
	_ftprintf( WSL_DBG_STREAM, _T( "The UNICODE/_UNICODE macro has NOT been defined.\n" ) );
#endif
#if defined ( _DEBUG )
	_ftprintf( WSL_DBG_STREAM, _T( "The _DEBUG macro has been defined.\n" ) );
#else
	_ftprintf( WSL_DBG_STREAM, _T( "The _DEBUG macro has NOT been defined.\n" ) );
#endif
#endif
	_ftprintf( stdout, _T( " ** Syslog parameters are:\n" ) );
	_ftprintf( stdout, _T( "regpath(%d): HKLM\\{%s}\n" ), regpath_set, regpath );
	_ftprintf( stdout, _T( "noreg: {%d}\n" ), no_reg );
	_ftprintf( stdout, _T( "norun: {%d}\n" ), no_run );
	_ftprintf( stdout, _T( "using_stdout: {%d}\n" ), using_stdout );
	_ftprintf( stdout, _T( "logpath(%d): {%s}\n" ), logpath_set, logpath );
	_ftprintf( stdout, _T( "logname(%d): {%s}\n" ), logname_set, logname );
	_ftprintf( stdout, _T( "logext(%d): {%s}\n" ), logextension_set, logextension );
	_ftprintf( stdout, _T( "logrotate(%d): {%s}\n" ), logrotate_condition_set, dt_compare_string[ logrotate_condition ] );
	_ftprintf( stdout, _T( "replacement(%d): {%c}\n" ), replacement_set, replacement );
	_ftprintf( stdout, _T( "filter(%d): {%d}\n" ), filter_set, filter );
	_ftprintf( stdout, _T( "ownfilter(%d): {%d}\n" ), own_filter_set, own_filter );
	_ftprintf( stdout, _T( "logdate(%d): {%d}\n" ), log_date_set, log_date );
	_ftprintf( stdout, _T( "logtime(%d): {%d}\n" ), log_time_set, log_time );
	_ftprintf( stdout, _T( "logmsec(%d): {%d}\n" ), log_msec_set, log_msec );
	_ftprintf( stdout, _T( "logip(%d): {%d}\n" ), log_ip_set, log_ip );
	_ftprintf( stdout, _T( "Windows EoL(%d): {%d}\n" ), newline_with_CR_set, newline_with_CR );
	_ftprintf( stdout, _T( "markreadonly(%d): {%d}\n" ), mark_as_readonly_set, mark_as_readonly );
	_ftprintf( stdout, _T( "flush(%d): {%d}\n" ), flush_set, flush );
	if( num_regex == 0 )
		_ftprintf( stdout, _T( "(no regular expressions are set)\n" ) );
	else
	{
#if ( _MSC_VER < 1900 )
		_ftprintf( stdout, _T( "regular expressions are (total %Iu of %Iu possible):\n" ), num_regex, max_regex );
#else
		_ftprintf( stdout, _T( "regular expressions are (total %zu of %zu possible):\n" ), num_regex, max_regex );
#endif
		for( size_t i = 0; i < num_regex; ++i )
		{
			switch( regex_tests[ i ].mode )
			{
			case syslog_params_t::regex_mode::drop:
				_ftprintf( stdout, _T(" drop: ") );
				break;
			case syslog_params_t::regex_mode::trim:
				_ftprintf( stdout, _T(" trim: ") );
				break;
			case syslog_params_t::regex_mode::pass:
				_ftprintf( stdout, _T(" pass: ") );
				break;
			default:
				_ftprintf( stdout, _T( " unknown action (%d): " ), regex_tests[ i ].mode );
			}
			_ftprintf( stdout, _T( "{%hs}\n" ), regex_tests[ i ].regex.expression );
		}
	}
	_ftprintf( stdout, _T( "port(%d): {%d}\n" ), port_set, ntohs( port ) );
}
